package com.feather.common.web;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Hex;

import redis.clients.jedis.Jedis;

import com.alibaba.fastjson.JSON;
import com.feather.common.data.DataColumn;
import com.feather.common.data.DataRow;
import com.feather.common.data.DataRowCollection;
import com.feather.common.data.DataSet;
import com.feather.common.data.DataTable;
import com.feather.common.log.LogProvider;
import com.feather.common.log.Logger;
import com.feather.common.text.StringUtil;
import com.feather.common.util.GZipUtil;
import com.feather.common.util.RuntimeError;
import com.feather.tenia.Procedure;
import com.feather.tenia.Tenia;
import com.feather.tenia.TeniaFactory;
import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.MimeUtility;

/**
 * @author flogyin
 */
public class JeWeb {
	public static String getIncludeRequestUri(ServletRequest request) {
		return (String) request.getAttribute("javax.servlet.include.request_uri");
	}

	public static String getIncludeRequestUri(HttpServletRequest request) {
		return (String) request.getAttribute("javax.servlet.include.request_uri");
	}

	public static boolean isIncludeRequest(ServletRequest request) {
		return (request.getAttribute("javax.servlet.include.request_uri") != null);
	}

	public static boolean isIncludeRequest(HttpServletRequest request) {
		return (request.getAttribute("javax.servlet.include.request_uri") != null);
	}

	public static boolean canTrim(HttpServletRequest request, String name) {
		return request != null ? request.getParameter(name + "^") == null : false;
	}

	public static boolean canConcat(HttpServletRequest request, String name) {
		return request != null ? request.getParameter(name + "+") != null : false;
	}

	public static boolean isMultipart(HttpServletRequest request) {
		String contentType = request != null ? request.getContentType() : null;
		return contentType != null && contentType.toLowerCase().startsWith("multipart/");
	}

	public static String getFrom(HttpServletRequest request) {
		String from = null;
		if (request != null) {
			from = request.getHeader("X-Forwarded-For");
			if (from == null || from.length() == 0 || "unknown".equalsIgnoreCase(from)) {
				from = request.getHeader("Proxy-Client-IP");
			}
			if (from == null || from.length() == 0 || "unknown".equalsIgnoreCase(from)) {
				from = request.getHeader("WL-Proxy-Client-IP");
			}
			if (from == null || from.length() == 0 || "unknown".equalsIgnoreCase(from)) {
				from = request.getHeader("x-real-ip");
			}
			if (from == null || from.length() == 0 || "unknown".equalsIgnoreCase(from)) {
				from = request.getRemoteAddr();
			}
		}
		return from;
	}

	public static String getBasePath(HttpServletRequest request) {
		return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/";
	}

	public static String getURI(HttpServletRequest request) {
		String queryString = request.getQueryString();
		return request.getRequestURI() + (queryString != null && queryString.length() > 0 ? "?" + queryString : "");
	}

	public static String getUriFolder(HttpServletRequest request) {
		return request.getRequestURI().substring(0, request.getRequestURI().lastIndexOf("/"));
	}

	public static String getUriParent(HttpServletRequest request) {
		String folder = getUriFolder(request);
		return folder.substring(0, folder.lastIndexOf("/"));
	}

	// url
	public static String getUrlFileName(String url) {
		if (url != null) {
			int at = url.indexOf('?');
			if (at > 0) {
				url = url.substring(0, at);
			}
			at = url.lastIndexOf('\\');
			if (at < 0) {
				at = url.lastIndexOf('/');
			}
			return at > -1 ? url.substring(at + 1) : url;
		}
		return null;
	}

	public static String getUrlSuffix(String url, boolean withDot) {
		if (url != null) {
			int at = url.indexOf('?');
			if (at > 0) {
				url = url.substring(0, at);
			}
			at = url.lastIndexOf('.');
			return at > -1 ? url.substring(at + (withDot ? 0 : 1)) : null;
		}
		return null;
	}

	public static String getUrlSuffixLowerCase(String url, boolean withDot) {
		String suffix = getUrlSuffix(url, withDot);
		return suffix != null ? suffix.toLowerCase() : null;
	}

	public static String encodeFileName(HttpServletRequest request, String name) throws Exception {
		String charset = RequestEnvironment.CURRENT[0].getRequestEncoding(request);
		String encodeName = URLEncoder.encode(name, charset);
		String rtn = "filename=\"" + encodeName + "\"";
		if (request != null) {
			String userAgent = request.getHeader("User-Agent");
			if (userAgent != null) {
				userAgent = userAgent.toLowerCase();
				// IE浏览器，只能采用URLEncoder编码
				if (userAgent.indexOf("msie") != -1) {
					encodeName = StringUtil.replace(encodeName, "+", "%20");
					rtn = "filename=\"" + encodeName + "\"";
				}
				// Opera浏览器只能采用filename*
				else if (userAgent.indexOf("opera") != -1) {
					rtn = "filename*=" + charset + "''" + encodeName;
				}
				// Safari浏览器，只能采用ISO编码的中文输出
				else if (userAgent.indexOf("safari") != -1) {
					rtn = "filename=\"" + new String(name.getBytes(charset), "ISO8859-1") + "\"";
				}
				// Chrome浏览器，只能采用MimeUtility编码或ISO编码的中文输出
				else if (userAgent.indexOf("applewebkit") != -1) {
					encodeName = MimeUtility.encodeText(name, charset, "B");
					rtn = "filename=\"" + encodeName + "\"";
				}
				// FireFox浏览器，可以使用MimeUtility或filename*或ISO编码的中文输出
				else if (userAgent.indexOf("mozilla") != -1) {
					encodeName = StringUtil.replace(encodeName, "+", "%20");
					rtn = "filename*=" + charset + "''" + encodeName;
				}
			}
		}
		return rtn;
	}

	// web keys
	@SuppressWarnings("unchecked")
	public static List<XFileItem> getFilterUploads(HttpServletRequest request) {
		return request != null ? (List<XFileItem>) request.getAttribute(KeyName.FilterUploads.name) : null;
	}

	public static void setFilterUploads(HttpServletRequest request, List<XFileItem> list) {
		if (request != null) {
			if (list != null)
				request.setAttribute(KeyName.FilterUploads.name, list);
			else
				request.removeAttribute(KeyName.FilterUploads.name);
		}
	}

	public static String getFilterAction(HttpServletRequest request) {
		return request != null ? (String) request.getAttribute(KeyName.FilterAction.name) : "";
	}

	public static void setFilterAction(HttpServletRequest request, String action) {
		if (request != null) {
			if (action != null)
				request.setAttribute(KeyName.FilterAction.name, action);
			else
				request.removeAttribute(KeyName.FilterAction.name);
		}
	}

	public static Object getFilterResult(HttpServletRequest request) {
		return request != null ? request.getAttribute(KeyName.FilterResult.name) : null;
	}

	public static void setFilterResult(HttpServletRequest request, Object result) {
		if (request != null) {
			if (result != null)
				request.setAttribute(KeyName.FilterResult.name, result);
			else
				request.removeAttribute(KeyName.FilterResult.name);
		}
	}

	public static String getRequestBefore(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestBefore.name);
	}

	public static String getRequestAfter(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestAfter.name);
	}

	public static String getRequestCatalog(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestCatalog.name);
	}

	public static String getRequestPkg(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestPkg.name);
	}

	public static String getRequestCom(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestCom.name);
	}

	public static String getRequestGrant(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestGrant.name);
	}

	public static long getRequestIssue(HttpServletRequest request) {
		return JeWeb.asLong(request, KeyName.RequestIssue.name);
	}

	public static long getRequestExpiry(HttpServletRequest request) {
		return JeWeb.asLong(request, KeyName.RequestExpiry.name);
	}

	public static String getRequestToken(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestToken.name);
	}

	public static String getRequestBid(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestBid.name);
	}

	public static String getRequestClass(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestClass.name);
	}

	public static String getRequestVersion(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestVersion.name);
	}

	public static String getRequestCrypto(HttpServletRequest request) {
		return JeWeb.asString(request, KeyName.RequestCrypto.name);
	}

	public static boolean isAckDone(HttpServletRequest request) {
		return request != null ? request.getAttribute(KeyName.AckDone.name) != null : false;
	}

	public static void setAckDone(HttpServletRequest request, boolean flag) {
		if (request != null) {
			if (flag)
				request.setAttribute(KeyName.AckDone.name, Boolean.TRUE);
			else
				request.removeAttribute(KeyName.AckDone.name);
		}
	}

	public static boolean isAckStream(HttpServletRequest request) {
		return request != null ? request.getAttribute(KeyName.AckIsStream.name) != null : false;
	}

	public static void setAckStream(HttpServletRequest request, boolean flag) {
		if (request != null) {
			if (flag)
				request.setAttribute(KeyName.AckIsStream.name, Boolean.TRUE);
			else
				request.removeAttribute(KeyName.AckIsStream.name);
		}
	}

	public static boolean isAckCompress(HttpServletRequest request) {
		return request != null ? request.getAttribute(KeyName.AckIsStream.name) != null : false;
	}

	public static void setAckCompress(HttpServletRequest request, boolean flag) {
		if (request != null) {
			if (flag)
				request.setAttribute(KeyName.AckIsStream.name, Boolean.TRUE);
			else
				request.removeAttribute(KeyName.AckIsStream.name);
		}
	}

	public static Object getSessionAttribute(HttpServletRequest request, String name) {
		HttpSession session = request != null ? request.getSession(false) : null;
		return session != null ? session.getAttribute(name) : null;
	}

	public static void setSessionAttribute(HttpServletRequest request, String name, Object obj) {
		HttpSession session = request != null ? request.getSession(true) : null;
		if (session != null)
			session.setAttribute(name, obj);
	}

	public static boolean ack(HttpServletRequest request, HttpServletResponse response, Object object) {
		String json = Server.CURRENT[0].toJson(object);
		response.setContentType("text/javascript; charset=utf-8");
		try {
			if (isAckStream(request)) {
				response.getOutputStream().write(json.getBytes("UTF-8"));
			} else {
				if (isAckCompress(request)) {
					response.setHeader("Content-Encoding", "gzip");
					response.getWriter().print(GZipUtil.compress(json.getBytes("UTF-8")));
				} else
					response.getWriter().print(json);
			}
			JeWeb.setAckDone(request, true);
		} catch (IOException ex) {
			String url = request != null ? request.getRequestURL().toString() : "";

			Logger log = LogProvider.CURRENT[0].createLogger();
			log.setSource("ack");
			log.setMethod(url);
			log.setMessage(ex);
			log.log(object);
			return false;
		}

		Logger ackLog = LogProvider.CURRENT[0].createPrinter();
		ackLog.setMessage(json);
		ackLog.print();

		if (LogProvider.CURRENT[0].isDebug()) {
			Map<String, List<String>> headMap = new LinkedHashMap<String, List<String>>();
			Collection<String> headNames = response.getHeaderNames();
			for (String name : headNames) {
				List<String> arr = new ArrayList<String>();
				arr.addAll(response.getHeaders(name));
				headMap.put(name, arr);
			}

			Logger headLog = LogProvider.CURRENT[0].createPrinter();
			headLog.setMessage(headMap);
			headLog.print();
		}
		return true;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Map<String, Object> getArgument(HttpServletRequest request) {
		Map<String, Object> argument = null;
		if (request != null) {
			argument = new LinkedHashMap();
			Enumeration<String> enumeration = request.getParameterNames();
			while (enumeration.hasMoreElements()) {
				String key = enumeration.nextElement();
				String[] val = request.getParameterValues(key);
				if (val == null || val.length == 0) {
					continue;
				}
				boolean trim = JeWeb.canTrim(request, key);
				if (val.length == 1 || !JeWeb.canConcat(request, key)) {
					argument.put(key.trim(), val[0] == null || !trim ? val[0] : val[0].trim());
				} else {
					StringBuilder builder = new StringBuilder(64);
					for (String v : val) {
						if (v != null && trim) {
							v = v.trim();
						}
						if (v == null || v.length() == 0) {
							continue;
						}
						if (builder.length() > 0) {
							builder.append(",");
						}
						builder.append(v);
					}
					argument.put(key.trim(), builder.toString());
				}
			}
			List<XFileItem> upload = JeWeb.getFilterUploads(request);
			if (upload != null) {
				for (XFileItem f : upload)
					argument.put(f.getFieldName(), f);
			}
			RequestEnvironment.CURRENT[0].custom(request, argument);
		}
		return argument;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static List<Map<String, Object>> listArgument(HttpServletRequest request) {
		List<Map<String, Object>> list = null;
		if (request != null) {
			Map<String, Object> argument = getArgument(request);
			list = new ArrayList<Map<String, Object>>();
			if (argument != null) {
				boolean hasArray = false;
				Map normalMap = new LinkedHashMap();
				for (Map.Entry<String, Object> entry : argument.entrySet()) {
					String key = entry.getKey();
					int at = key.indexOf('[');
					if (at > 0 && key.charAt(key.length() - 1) == ']') {
						try {
							String indexChars = key.substring(at + 1, key.length() - 1);
							Integer.parseInt(indexChars, 10);
							hasArray = true;
							continue;
						} catch (NumberFormatException ex) {
						}
					}
					normalMap.put(key, entry.getValue());
				}
				if (hasArray) {
					Map<String, Map> indexMap = new HashMap<String, Map>();
					for (Map.Entry<String, Object> entry : argument.entrySet()) {
						String key = entry.getKey();
						int at = key.indexOf('[');
						if (at > 0 && key.charAt(key.length() - 1) == ']') {
							try {
								String indexChars = key.substring(at + 1, key.length() - 1);
								Integer.parseInt(indexChars, 10);
								Map arrMap = indexMap.get(indexChars);
								if (arrMap == null) {
									arrMap = new LinkedHashMap();
									arrMap.putAll(normalMap);
									indexMap.put(indexChars, arrMap);
								}
								arrMap.put(key.substring(0, at), entry.getValue());
							} catch (NumberFormatException ex) {
							}
						}
					}
					for (Map map : indexMap.values())
						list.add(map);
				} else
					list.add(argument);
			}
			int listSize = list.size();
			if (listSize > 0) {
				String firstKey = KeyName.ArgumentListFirst.name;
				if (firstKey != null && firstKey.length() > 0) {
					Map firstMap = list.get(0);
					firstMap.put(firstKey, "1");
				}
				String lastKey = KeyName.ArgumentListLast.name;
				if (lastKey != null && lastKey.length() > 0) {
					Map lastMap = list.get(listSize - 1);
					lastMap.put(lastKey, "1");
				}
			}
		}
		return list;
	}

	// //
	// // String tool
	// //
	public static String standby(String value, String standby) {
		return (value == null || value.length() == 0) && standby != null ? standby : value;
	}

	public static String trim(String value) {
		return value != null ? value.trim() : "";
	}

	public static String trimNull(String value) {
		if (value != null) {
			value = value.trim();
			if (value.length() == 0)
				value = null;
		}
		return value;
	}

	public static String substr(String text, int max) {
		if (text == null || max == 0) {
			return "";
		}
		int length = text.length();
		if (length <= max) {
			return text;
		}
		if (max > 0) {
			return text.substring(0, max);
		}
		max = length + max;
		return max >= 0 ? text.substring(max) : text;
	}

	public static String subRight(String text, int max) {
		if (text == null || max == 0) {
			return "";
		}
		return text.length() > max && max > -1 ? text.substring(0, max) : text;
	}

	public static String toHtml(String text) {
		if (text != null) {
			text = StringUtil.replace(text, "&", "&amp;");
			text = StringUtil.replace(text, "<", "&lt;");
			text = StringUtil.replace(text, ">", "&gt;");
			text = StringUtil.replace(text, "\"", "&quot;");
			text = StringUtil.replace(text, "'", "&#39;");
			// text = StringUtil.replace(text, " ", "&nbsp;");
		} else {
			text = "";
		}
		return text;
	}

	public static String toJs(String text) {
		if (text == null) {
			return "";
		}
		text = StringUtil.replace(text, "'", "\\'");
		text = StringUtil.replace(text, "\"", "\\\"");
		text = StringUtil.replace(text, "\r", "\\r");
		text = StringUtil.replace(text, "\n", "\\n");
		return text;
	}

	public static String toQueryString(Map<String, Object> map, String charset) {
		boolean isEncoding = charset != null && charset.length() > 0;
		StringBuilder builder = new StringBuilder();
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			String value = "";
			if (entry != null) {
				if (isEncoding) {
					try {
						value = URLEncoder.encode(value, entry.toString());
					} catch (UnsupportedEncodingException ex) {
						throw new RuntimeException(ex);
					}
				} else {
					value = entry.toString();
				}
			}
			if (builder.length() > 0) {
				builder.append("&");
			}
			builder.append(entry.getKey()).append('=').append(value);
		}
		return builder.toString();
	}

	// //
	// //BEGIN: as byte
	// //
	public static byte asByte(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? Byte.parseByte(str, 10) : 0;
	}

	public static byte asByte(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? Byte.parseByte(str, 10) : 0;
	}

	public static byte asByte(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asByte();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0;
	}

	public static byte asByte(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asByte(rows.get(0), name) : 0;
	}

	// //
	// //BEGIN: as short
	// //
	public static short asShort(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? Short.parseShort(str, 10) : 0;
	}

	public static short asShort(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? Short.parseShort(str, 10) : 0;
	}

	public static short asShort(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asShort();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0;
	}

	public static short asShort(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asShort(rows.get(0), name) : 0;
	}

	// //
	// //BEGIN: as char
	// //
	public static char asChar(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? str.charAt(0) : 0;
	}

	public static char asChar(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? str.charAt(0) : 0;
	}

	public static char asChar(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null) {
				String str = dc.asString();
				return str.length() > 0 ? str.charAt(0) : 0;
			} else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0;
	}

	public static char asChar(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asChar(rows.get(0), name) : 0;
	}

	// //
	// //BEGIN: as int
	// //
	public static int asInt(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? Integer.parseInt(str, 10) : 0;
	}

	public static int asInt(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? Integer.parseInt(str, 10) : 0;
	}

	public static int asInt(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asInt();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0;
	}

	public static int asInt(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asInt(rows.get(0), name) : 0;
	}

	// //
	// //BEGIN: as long
	// //
	public static long asLong(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? Long.parseLong(str, 10) : 0L;
	}

	public static long asLong(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? Long.parseLong(str, 10) : 0L;
	}

	public static long asLong(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asLong();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0;
	}

	public static long asLong(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asLong(rows.get(0), name) : 0L;
	}

	// //
	// //BEGIN: as float
	// //
	public static float asFloat(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? Float.parseFloat(str) : 0F;
	}

	public static float asFloat(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? Float.parseFloat(str) : 0F;
	}

	public static float asFloat(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asFloat();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0F;
	}

	public static float asFloat(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asFloat(rows.get(0), name) : 0F;
	}

	// //
	// //BEGIN: as float
	// //
	public static double asDouble(HttpServletRequest request, String name) {
		String str = asString(request, name);
		return str.length() > 0 ? Double.parseDouble(str) : 0D;
	}

	public static double asDouble(Map<String, Object> map, String name) {
		String str = asString(map, name);
		return str.length() > 0 ? Double.parseDouble(str) : 0D;
	}

	public static double asDouble(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asDouble();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return 0D;
	}

	public static double asDouble(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asDouble(rows.get(0), name) : 0D;
	}

	// //
	// //as String
	// //
	public static String asString(HttpServletRequest request, String name) {
		String value = null;
		boolean trim = true;
		if (request != null && name != null) {
			value = request.getParameter(name);
			trim = JeWeb.canTrim(request, name);
		}
		return value != null ? (trim ? value.trim() : value) : "";
	}

	public static String asString(HttpServletRequest request, String name, String standby) {
		return JeWeb.standby(JeWeb.asString(request, name), standby);
	}

	public static String asString(Map<String, ?> map, String name) {
		if (map != null) {
			if (map.containsKey(name)) {
				Object value = map.get(name);
				if (value instanceof Object[]) {
					Object[] array = (Object[]) value;
					value = array.length > 0 ? array[0] : null;
				}
				return value != null ? value.toString() : "";
			} else {
				RequestEnvironment.CURRENT[0].notFoundName(map, name);
			}
		}
		return "";
	}

	public static String asString(Map<String, ?> map, String name, String standby) {
		return JeWeb.standby(JeWeb.asString(map, name), standby);
	}

	public static String asString(Map<String, ?> map, String name, int length) {
		return JeWeb.substr(JeWeb.asString(map, name), length);
	}

	public static String asString(Map<String, ?> map, String name, int length, String standby) {
		return JeWeb.standby(JeWeb.asString(map, name, length), standby);
	}

	public static String asString(DataRow row, String name) {
		if (row != null) {
			DataColumn dc = row.get(name);
			if (dc != null)
				return dc.asString();
			else
				RequestEnvironment.CURRENT[0].notFoundName(row, name);
		}
		return "";
	}

	public static String asString(DataRow row, String name, String standby) {
		return JeWeb.standby(JeWeb.asString(row, name), standby);
	}

	public static String asString(DataRow row, String name, int length) {
		return JeWeb.substr(JeWeb.asString(row, name), length);
	}

	public static String asString(DataRow row, String name, int length, String standby) {
		return JeWeb.standby(JeWeb.asString(row, name, length), standby);
	}

	public static String asString(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asString(rows.get(0), name) : "";
	}

	public static String asString(DataRowCollection rows, String name, String standby) {
		return JeWeb.standby(JeWeb.asString(rows, name), standby);
	}

	public static String asString(DataRowCollection rows, String name, int length) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asString(rows.get(0), name, length) : "";
	}

	public static String asString(DataRowCollection rows, String name, int length, String standby) {
		return JeWeb.standby(JeWeb.asString(rows, name, length), standby);
	}

	// //
	// //as html
	// //
	public static String asHtml(HttpServletRequest request, String name) {
		return JeWeb.toHtml(JeWeb.asString(request, name));
	}

	public static String asHtml(Map<String, ?> map, String name) {
		return JeWeb.toHtml(JeWeb.asString(map, name));
	}

	public static String asHtml(Map<String, ?> map, String name, int length) {
		return JeWeb.toHtml(JeWeb.asString(map, name, length));
	}

	public static String asHtml(DataRow row, String name) {
		return JeWeb.toHtml(JeWeb.asString(row, name));
	}

	public static String asHtml(DataRow row, String name, int length) {
		return JeWeb.toHtml(JeWeb.asString(row, name, length));
	}

	public static String asHtml(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asString(rows.get(0), name) : "";
	}

	public static String asHtml(DataRowCollection rows, String name, int length) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asHtml(rows.get(0), name, length) : "";
	}

	// //
	// //as js
	// //
	public static String asJs(Map<String, ?> map, String name) {
		return JeWeb.toJs(JeWeb.asString(map, name));
	}

	public static String asJs(Map<String, ?> map, String name, int length) {
		return JeWeb.toJs(JeWeb.asString(map, name, length));
	}

	public static String asJs(DataRow row, String name) {
		return JeWeb.toJs(JeWeb.asString(row, name));
	}

	public static String asJs(DataRow row, String name, int length) {
		return JeWeb.toJs(JeWeb.asString(row, name, length));
	}

	public static String asJs(DataRowCollection rows, String name) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asJs(rows.get(0), name) : "";
	}

	public static String asJs(DataRowCollection rows, String name, int length) {
		return rows != null && rows.getCount() > 0 ? JeWeb.asJs(rows.get(0), name, length) : "";
	}

	// //
	// //generate options
	// //
	public static String options(Object[] array) {
		return options(array, null);
	}

	public static String options(Object[] array, Object selected) {
		StringBuilder builder = new StringBuilder(64);
		int length = array != null ? array.length : 0;
		for (int i = 0; i + 1 < length; i += 2) {
			String key = array[i].toString();
			String tag = array[i + 1].toString();
			builder.append("<option value=\"");
			builder.append(key);
			builder.append("\"");
			if (selected != null && selected.equals(key)) {
				builder.append(" selected");
			}
			builder.append(">");
			builder.append(tag);
			builder.append("</option>");
		}
		return builder.toString();
	}

	public static String optionsLinear(Object[] array, Object selected)// 值和标签相同
	{
		StringBuilder builder = new StringBuilder(64);
		int length = array != null ? array.length : 0;
		for (int i = 0; i < length; i++) {
			String item = array[i].toString();
			builder.append("<option value=\"");
			builder.append(item);
			builder.append("\"");
			if (selected != null && selected.equals(item)) {
				builder.append(" selected");
			}
			builder.append(">");
			builder.append(item);
			builder.append("</option>");
		}
		return builder.toString();
	}

	public static String options(List<?> list, Object selected) {
		StringBuilder builder = new StringBuilder(64);
		int size = list != null ? list.size() : 0;
		for (int i = 0; i + 1 < size; i += 2) {
			String key = list.get(i).toString();
			String tag = list.get(i + 1).toString();
			builder.append("<option value=\"");
			builder.append(key);
			builder.append("\"");
			if (selected != null && selected.equals(key)) {
				builder.append(" selected");
			}
			builder.append(">");
			builder.append(tag);
			builder.append("</option>");
		}
		return builder.toString();
	}

	public static String optionsLinear(List<?> list, Object selected)// 值和标签相同
	{
		StringBuilder builder = new StringBuilder(64);
		int size = list != null ? list.size() : 0;
		for (int i = 0; i < size; i++) {
			String item = list.get(i).toString();
			builder.append("<option value=\"");
			builder.append(item);
			builder.append("\"");
			if (selected != null && selected.equals(item)) {
				builder.append(" selected");
			}
			builder.append(">");
			builder.append(item);
			builder.append("</option>");
		}
		return builder.toString();
	}

	public static String options(Map<String, ?> map, Object selected) {
		StringBuilder builder = new StringBuilder(64);
		if (map != null) {
			for (Map.Entry<String, ?> entry : map.entrySet()) {
				String key = entry.getKey();
				Object obj = entry.getValue();
				String tag = obj != null ? obj.toString() : "";
				builder.append("<option value=\"");
				builder.append(key);
				builder.append("\"");
				if (selected != null && selected.equals(key)) {
					builder.append(" selected");
				}
				builder.append(">");
				builder.append(tag);
				builder.append("</option>");
			}
		}
		return builder.toString();
	}

	public static String options(DataTable table) {
		return options(table, "");
	}

	public static String options(DataTable table, Object selected) {
		if (selected == null) {
			selected = "";
		}
		return table != null ? options(table.getRows()) : "";
	}

	public static String options(DataRowCollection rows) {
		return options(rows, "");
	}

	public static String options(DataRowCollection rows, Object selected) {
		if (selected == null) {
			selected = "";
		}
		StringBuilder builder = new StringBuilder(64);
		if (rows != null) {
			int rowsCount = rows.getCount();
			int colsCount = 0;
			if (rowsCount > 0 && (colsCount = rows.get(0).getCount()) > 0) {
				for (int i = 0; i < rowsCount; i++) {
					DataRow item = rows.get(i);
					String value = item.get(0).asString();
					String label = colsCount > 1 ? item.get(1).asString() : value;
					builder.append("<option value=\"");
					builder.append(JeWeb.toHtml(value));
					builder.append("\"");
					if (selected.equals(value)) {
						builder.append(" selected");
					}
					builder.append(">");
					builder.append(JeWeb.toHtml(label));
					builder.append("</option>");
				}
			}
		}
		return builder.toString();
	}

	public static String optionsDictionary(HttpServletRequest request, String dicNode) throws Exception {
		return optionsDictionary(request, dicNode, null);
	}

	public static String optionsDictionary(HttpServletRequest request, String dicNode, String selected) throws Exception {
		List<Map<String, String>> dicList = getDictionaryCache(request, dicNode);
		int size = dicList != null ? dicList.size() : 0;

		boolean isMulti = selected != null && selected.indexOf(",") != -1;

		StringBuilder builder = new StringBuilder(64);
		for (int i = 0; i < size; i++) {
			Map<String, String> dicMap = dicList.get(i);
			String id = dicMap.get("id");
			// String code = dicMap.get("code");
			String value = dicMap.get("value");
			// String shorts = dicMap.get("short");
			String name = dicMap.get("name");
			// String description = dicMap.get("description");
			builder.append("<option value=\"");
			builder.append(id);
			builder.append("\"");
			// if (code.equals(selected) || (isMulti &&
			// (selected.indexOf(code+",") != -1 || selected.indexOf(","+code)
			// != -1))) {
			if (id.equals(selected) || (isMulti && (selected.indexOf(id + ",") != -1 || selected.indexOf("," + id) != -1))) {
				builder.append(" selected");
			}
			if (name.length() > 0) {
				builder.append(" style=\"background:");
				builder.append(name);
				builder.append("\"");
			}
			builder.append(">");
			builder.append(value);
			builder.append("</option>");
		}
		return builder.toString();
	}

	// //
	// //action
	// //
	public static String action(String _pkg) {
		return action(null, null, null, _pkg, 0L);
	}

	public static String action(String _pkg, long _expiry) {
		return action(null, null, null, _pkg, _expiry);
	}

	public static String action(String _com, String _grant) {
		return action(null, _com, _grant, null, 0L);
	}

	public static String action(String _com, String _grant, long _expiry) {
		return action(null, _com, _grant, null, _expiry);
	}

	public static String action(String _com, String _grant, String _pkg) {
		return action(null, _com, _grant, _pkg, 0L);
	}

	public static String action(String _com, String _grant, String _pkg, long _expiry) {
		return action(null, _com, _grant, null, _expiry);
	}

	public static String actionBefore(String before, String _pkg, long _expiry) {
		return action(KeyName.RequestBefore.name + "=" + before, null, null, _pkg, _expiry);
	}

	public static String actionBefore(String before, String _pkg) {
		return action(KeyName.RequestBefore.name + "=" + before, null, null, _pkg, 0L);
	}

	public static String actionBefore(String before, String _com, String _grant) {
		return action(KeyName.RequestBefore.name + "=" + before, _com, _grant, null, 0L);
	}

	public static String actionBefore(String before, String _com, String _grant, long _expiry) {
		return action(KeyName.RequestBefore.name + "=" + before, _com, _grant, null, _expiry);
	}

	public static String actionBefore(String before, String _com, String _grant, String _pkg) {
		return action(KeyName.RequestBefore.name + "=" + before, _com, _grant, _pkg, 0L);
	}

	public static String actionBefore(String before, String _com, String _grant, String _pkg, long _expiry) {
		return action(KeyName.RequestBefore.name + "=" + before, _com, _grant, null, _expiry);
	}

	public static String actionAfter(String after, String _pkg, long _expiry) {
		return action(KeyName.RequestAfter.name + "=" + after, null, null, _pkg, _expiry);
	}

	public static String actionAfter(String after, String _pkg) {
		return action(KeyName.RequestAfter.name + "=" + after, null, null, _pkg, 0L);
	}

	public static String actionAfter(String after, String _com, String _grant) {
		return action(KeyName.RequestAfter.name + "=" + after, _com, _grant, null, 0L);
	}

	public static String actionAfter(String after, String _com, String _grant, long _expiry) {
		return action(KeyName.RequestAfter.name + "=" + after, _com, _grant, null, _expiry);
	}

	public static String actionAfter(String after, String _com, String _grant, String _pkg) {
		return action(KeyName.RequestAfter.name + "=" + after, _com, _grant, _pkg, 0L);
	}

	public static String actionAfter(String after, String _com, String _grant, String _pkg, long _expiry) {
		return action(KeyName.RequestAfter.name + "=" + after, _com, _grant, null, _expiry);
	}

	public static String action(String act, String _com, String _grant, String _pkg, long _expiry) {
		String param = params(_com, _grant, _pkg, _expiry);

		StringBuilder url = new StringBuilder(param.length() + 64);
		url.append(KeyName.FilterSuffix.name);
		url.append("?");
		if (act != null) {
			url.append(act);
			url.append("&");
		}
		url.append(param);
		return url.toString();
	}

	public static String params(String _com, String _grant, String _pkg, long _expiry) {
		if (_com != null) {
			_com = _com.trim();
		}
		if (_grant != null) {
			_grant = _grant.trim();
		}
		if (_pkg != null) {
			_pkg = _pkg.trim();
		}
		StringBuilder builder = new StringBuilder(64);
		if (_com != null && _com.length() > 0) {
			builder.append(KeyName.RequestCom.name);
			builder.append("=");
			builder.append(_com);
		}
		if (_grant != null && _grant.length() > 0) {
			if (builder.length() > 0) {
				builder.append("&");
			}
			builder.append(KeyName.RequestGrant.name);
			builder.append("=");
			builder.append(_grant);
		}
		if (_pkg != null && _pkg.length() > 0) {
			if (builder.length() > 0) {
				builder.append("&");
			}
			builder.append(KeyName.RequestPkg.name);
			builder.append("=");
			builder.append(_pkg);
		}

		if (builder.length() > 0) {
			builder.append("&");
			builder.append(KeyName.RequestIssue.name);
			builder.append("=");
			builder.append(System.currentTimeMillis());

			builder.append("&");
			builder.append(KeyName.RequestExpiry.name);
			builder.append("=");
			builder.append(_expiry);

			String digest = null;
			String text = builder.toString() + "!" + Server.CURRENT[0].getDigest();
			try {
				MessageDigest md5 = MessageDigest.getInstance("MD5");
				digest = Hex.encodeHexString(md5.digest(text.getBytes("utf-8")));
			} catch (Exception ex) {
				throw RuntimeError.create(ex);
			}

			builder.append("&");
			builder.append(KeyName.RequestToken.name);
			builder.append("=");
			builder.append(digest);
			return builder.toString();
		}
		throw new RuntimeException("未找到任何参数： " + KeyName.RequestCom.name + ", " + KeyName.RequestGrant.name + ", " + KeyName.RequestPkg.name);
	}

	// //
	// //check action
	// //
	public static boolean checkAction(String _com, String _grant, String _pkg, long _issue, long _expiry, String _token) {
		if (_pkg.length() > 0 && _token.length() == 0) {
			return false;
		}
		if (_expiry > 0 && System.currentTimeMillis() - _issue > _expiry) {
			return false;
		}
		StringBuilder builder = new StringBuilder(64);
		if (_com.length() > 0) {
			builder.append(KeyName.RequestCom.name);
			builder.append("=");
			builder.append(_com);
		}
		if (_grant.length() > 0) {
			if (builder.length() > 0) {
				builder.append("&");
			}
			builder.append(KeyName.RequestGrant.name);
			builder.append("=");
			builder.append(_grant);
		}
		if (_pkg.length() > 0) {
			if (builder.length() > 0) {
				builder.append("&");
			}
			builder.append(KeyName.RequestPkg.name);
			builder.append("=");
			builder.append(_pkg);
		}
		if (builder.length() > 0) {
			builder.append("&");
		}
		builder.append(KeyName.RequestIssue.name);
		builder.append("=");
		builder.append(_issue);

		builder.append("&");
		builder.append(KeyName.RequestExpiry.name);
		builder.append("=");
		builder.append(_expiry);

		if (builder.length() > 0) {
			String digest = null;
			String text = builder.toString() + "!" + Server.CURRENT[0].getDigest();
			try {
				MessageDigest md5 = MessageDigest.getInstance("MD5");
				digest = Hex.encodeHexString(md5.digest(text.getBytes("utf-8")));
			} catch (Exception ex) {
				throw RuntimeError.create(ex);
			}
			return digest.equals(_token);
		}
		return true;
	}

	public static boolean checkAccess(HttpServletRequest request, HttpServletResponse response) {
		String _com = JeWeb.getRequestCom(request);
		String _grant = JeWeb.getRequestGrant(request);
		String _pkg = JeWeb.getRequestPkg(request);
		String _token = JeWeb.getRequestToken(request);
		long _issue = JeWeb.getRequestIssue(request);
		long _expiry = JeWeb.getRequestExpiry(request);

		boolean check = JeWeb.checkAction(_com, _grant, _pkg, _issue, _expiry, _token);
		if (check && (_grant.length() == 0 || JeWeb.hasPermission(request, _com + "-" + _grant))) {
			return true;
		}
		return false;
	}

	// //
	// //about jdbc
	// //
	public static Tenia getTenia(HttpServletRequest request) {
		return TeniaFactory.get(JeWeb.getRequestCatalog(request));
	}

	public static Procedure getProcedure(HttpServletRequest request) throws SQLException {
		String pkg = JeWeb.getRequestPkg(request);
		return JeWeb.getProcedure(request, pkg);
	}

	public static Procedure getProcedure(HttpServletRequest request, String pkg) throws SQLException {
		Tenia tenia = JeWeb.getTenia(request);
		Procedure procedure = tenia != null ? tenia.getProcedure(pkg) : null;
		if (procedure == null) {
			RequestEnvironment.CURRENT[0].notFoundValue(request, KeyName.RequestPkg, pkg);
		}
		return procedure;
	}

	public static DataSet callProcedure(HttpServletRequest request) throws SQLException, Exception {
		List<DataSet> list = JeWeb.callProcedureL(request);
		return list != null ? list.get(0) : null;
	}

	public static List<DataSet> callProcedureL(HttpServletRequest request) throws SQLException, Exception {
		List<Map<String, Object>> argList = JeWeb.listArgument(request);
		return JeWeb.callProcedureL(getProcedure(request), argList);
	}

	public static DataSet callProcedure(HttpServletRequest request, String pkg) throws SQLException, Exception {
		List<DataSet> list = JeWeb.callProcedureL(request, pkg);
		return list != null ? list.get(0) : null;
	}

	public static List<DataSet> callProcedureL(HttpServletRequest request, String pkg) throws SQLException, Exception {
		Procedure procedure = JeWeb.getTenia(request).getProcedure(pkg);
		if (procedure == null) {
			RequestEnvironment.CURRENT[0].notFoundValue(request, KeyName.RequestPkg, pkg);
		}
		List<Map<String, Object>> argList = JeWeb.listArgument(request);
		return JeWeb.callProcedureL(procedure, argList);
	}

	public static DataSet callProcedure(HttpServletRequest request, Map<String, Object> argument) throws SQLException, Exception {
		Procedure procedure = JeWeb.getProcedure(request);
		if (procedure == null) {
			RequestEnvironment.CURRENT[0].notFoundValue(request, KeyName.RequestPkg, null);
		}
		return procedure.call(argument);
	}

	public static DataSet callProcedure(HttpServletRequest request, String pkg, Map<String, Object> argument) throws SQLException, Exception {
		Procedure procedure = JeWeb.getProcedure(request, pkg);
		return procedure.call(argument);
	}

	protected static List<DataSet> callProcedureL(Procedure procedure, List<Map<String, Object>> argList) throws SQLException, Exception {
		List<DataSet> list = null;
		if (procedure != null && argList != null) {
			int count = argList.size();
			if (count == 1) {
				list = new ArrayList<DataSet>();
				list.add(procedure.call(argList.get(0)));
			} else if (count > 1) {
				list = new ArrayList<DataSet>();
				for (Map<String, Object> argument : argList)
					list.add(procedure.call(argument));
			}
		}
		return list;
	}

	public static DataTable executeQuery(HttpServletRequest request, String sql) throws SQLException, Exception {
		Map<String, Object> argument = JeWeb.getArgument(request);
		DataTable table = JeWeb.getTenia(request).executeQuery(sql, argument);
		return table;
	}

	public static void executeSQL(HttpServletRequest request, String sql) throws SQLException {
		JeWeb.getTenia(request).execute(sql, JeWeb.getArgument(request));
	}

	// //
	// //about login
	// //
	public static Object getLoginObject(HttpServletRequest request) {
		return RequestEnvironment.CURRENT[0].getLoginObject(request.getSession(false));
	}

	public static Object getLoginObject(HttpSession session) {
		return RequestEnvironment.CURRENT[0].getLoginObject(session);
	}

	public static void setLoginObject(HttpServletRequest request, Object object) {
		RequestEnvironment.CURRENT[0].setLoginObject(request.getSession(false), object);
	}

	public static void setLoginObject(HttpSession session, Object object) {
		RequestEnvironment.CURRENT[0].setLoginObject(session, object);
	}

	public static void removeLoginObject(HttpSession session) {
		RequestEnvironment.CURRENT[0].removeLoginObject(session);
	}

	public static String getLoginInfo(HttpServletRequest request, String name) {
		return RequestEnvironment.CURRENT[0].getLoginInfo(request.getSession(false), name);
	}

	public static String getLoginInfo(HttpSession session, String name) {
		return RequestEnvironment.CURRENT[0].getLoginInfo(session, name);
	}

	public static String getLoginInfo(Object object, String name) {
		return RequestEnvironment.CURRENT[0].getLoginInfo(object, name);
	}

	public static boolean isSA(HttpServletRequest request) {
		return RequestEnvironment.CURRENT[0].isSA(request.getSession(false));
	}

	public static boolean isSA(HttpSession session) {
		return RequestEnvironment.CURRENT[0].isSA(session);
	}

	public static boolean isSA(Object object) {
		return RequestEnvironment.CURRENT[0].isSA(object);
	}

	public static boolean hasLogin(HttpSession session) {
		return RequestEnvironment.CURRENT[0].isSA(session);
	}

	public static boolean hasLogin(HttpServletRequest request) {
		return RequestEnvironment.CURRENT[0].hasLogin(request.getSession(false));
	}

	public static boolean hasPermission(HttpServletRequest request, String code) {
		return RequestEnvironment.CURRENT[0].hasPermission(request.getSession(false), code);
	}

	public static boolean hasPermission(HttpSession session, String code) {
		return RequestEnvironment.CURRENT[0].hasPermission(session, code);
	}

	public static String getPermissionName(HttpServletRequest request, String code) {
		return RequestEnvironment.CURRENT[0].getPermissionName(request, code);
	}

	// //
	// //cache
	// //
	public static Map<String, String> getMapCache(HttpServletRequest request, String prefix, String code) {
		Map<String, String> map = null;
		if (code != null) {
			String jrKey = prefix + ":" + code;
			try (Jedis jedis = JedisPoolInfo.CURRENT[0].getJedis()) {
				map = jedis.hgetAll(jrKey);
			}
			if (map == null) {
				map = RequestEnvironment.CURRENT[0].getCacheMap(request, prefix, code);
				if (map != null) {
					try (Jedis jedis = JedisPoolInfo.CURRENT[0].getJedis()) {
						jedis.hmset(jrKey, map);
					}
				}
			}
		}
		return map;
	}

	@SuppressWarnings("unchecked")
	public static List<Map<String, String>> getDictionaryCache(HttpServletRequest request, String dicNode) {
		List<Map<String, String>> list = null;
		if (dicNode != null) {
			String json = null;
			String jrKey = RequestEnvironment.CURRENT[0].getCacheDictionaryPrefix(request) + dicNode;
			try (Jedis jedis = JedisPoolInfo.CURRENT[0].getJedis()) {
				json = jedis.get(jrKey);
			}
			if (json != null) {
				list = JSON.parseObject(json, List.class);
			} else {
				list = RequestEnvironment.CURRENT[0].getCacheDictionary(request, dicNode);
				if (list != null) {
					json = Server.CURRENT[0].toJson(list);
					try (Jedis jedis = JedisPoolInfo.CURRENT[0].getJedis()) {
						jedis.set(jrKey, json);
					}
				}
			}
		}
		return list;
	}

	public static Map<String, String> getDictionaryCache(HttpServletRequest request, String dicNode, String dicCode) {
		List<Map<String, String>> list = getDictionaryCache(request, dicNode);
		if (list != null) {
			for (Map<String, String> map : list)
				if (dicCode.equals(map.get("code")))
					return map;
		}
		return null;
	}

	public static String getDictionaryCache(HttpServletRequest request, String dicNode, String dicCode, String dicKey) {
		Map<String, String> dictionary = getDictionaryCache(request, dicNode, dicCode);
		String value = dictionary != null ? dictionary.get(dicKey) : null;
		return value != null ? value : "";
	}
}
